/** 【文件说明】：对象处理工具类
 *  【使用例子】：
 
    import { ObjectUtils } from '@/utils/objectUtils';

    // 在某个方法或生命周期钩子中使用
    const obj1 = { a: 1, b: { c: 2 } };
    const obj2 = { b: { d: 3 }, e: 4 };
    console.log(ObjectUtils.deepMergeObjects(obj1, obj2)); // 输出 { a: 1, b: { c: 2, d: 3 }, e: 4 }

    const obj = { a: 1, b: 2, c: 3 };
    console.log(ObjectUtils.getKeys(obj)); // 输出 ["a", "b", "c"]
    console.log(ObjectUtils.getEntries(obj)); // 输出 [["a", 1], ["b", 2], ["c", 3]]
    console.log(ObjectUtils.isEmpty({})); // 输出 true
    console.log(ObjectUtils.removeKey(obj, 'b')); // 输出 { a: 1, c: 3 }

    const queryParams = { name: 'John', age: '30' };
    console.log(ObjectUtils.toQueryString(queryParams)); // 输出 "name=John&age=30"
    console.log(ObjectUtils.fromQueryString('name=John&age=30')); // 输出 { name: "John", age: "30" }

    console.log(ObjectUtils.hasProperty(obj, 'a')); // 输出 true
    console.log(ObjectUtils.clone(obj)); // 输出 { a: 1, b: 2, c: 3 }

    const obj3 = { x: 10 };
    console.log(ObjectUtils.mergeObjects(obj1, obj2, obj3)); // 输出 { a: 1, b: { c: 2, d: 3 }, e: 4, x: 10 }
    
 */

export class ObjectUtils {
    /**
     * 深度合并两个对象
     * @param target 目标对象
     * @param source 源对象
     * @returns 返回合并后的对象
     */
    static deepMergeObjects<T, U>(target: T, source: U): T & U {
        const isObject = (obj: any) => obj && typeof obj === 'object' && !Array.isArray(obj);
    
        if (!isObject(target) || !isObject(source)) {
          return source as any;
        }
    
        // 获取源对象的所有键，并进行类型断言
        const sourceKeys = Object.keys(source as any) as Array<keyof T & keyof U>;
    
        for (const key of sourceKeys) {
          const targetValue = target[key] as any;
          const sourceValue = source[key];
    
          if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
            (target as any)[key] = this.mergeArrays(targetValue, sourceValue);
          } else if (isObject(targetValue) && isObject(sourceValue)) {
            target[key] = this.deepMergeObjects(targetValue, sourceValue);
          } else {
            (target as any)[key] = sourceValue;
          }
        }
    
        return target as T & U;
      }
  
    /**
     * 合并多个数组
     * @param arrays 要合并的数组列表
     * @returns 返回一个新的数组，包含所有输入数组的元素
     */
    private static mergeArrays<T>(...arrays: T[][]): T[] {
      return arrays.reduce((acc, val) => acc.concat(val), []);
    }
  
    /**
     * 获取对象的键名列表
     * @param obj 要获取键名的对象
     * @returns 返回一个包含对象键名的数组
     */
    static getKeys<T extends object>(obj: T): (keyof T)[] {
      return Object.keys(obj) as (keyof T)[];
    }
  
    /**
     * 获取对象的键值对列表
     * @param obj 要获取键值对的对象
     * @returns 返回一个包含键值对的数组
     */
    static getEntries<T extends object>(obj: T): Array<[keyof T, T[keyof T]]> {
      return Object.entries(obj) as Array<[keyof T, T[keyof T]]>;
    }
  
    /**
     * 判断对象是否为空
     * @param obj 要检查的对象
     * @returns 如果对象为空则返回 true，否则返回 false
     */
    static isEmpty(obj: object): boolean {
      return Object.keys(obj).length === 0;
    }
  
    /**
     * 删除对象中的指定键
     * @param obj 要删除键的对象
     * @param key 要删除的键
     * @returns 返回一个新的对象，不包含指定的键
     */
    static removeKey<T extends object, K extends keyof T>(obj: T, key: K): Omit<T, K> {
      const { [key]: _, ...rest } = obj;
      return rest;
    }
  
    /**
     * 将对象转换为查询字符串
     * @param obj 要转换的对象
     * @returns 返回查询字符串
     */
    static toQueryString(obj: { [key: string]: any }): string {
      return new URLSearchParams(obj).toString();
    }
  
    /**
     * 将查询字符串转换为对象
     * @param query 查询字符串
     * @returns 返回解析后的对象
     */
    static fromQueryString(query: string): { [key: string]: string } {
      const params = new URLSearchParams(query);
      const result: { [key: string]: string } = {};
      for (const [key, value] of params.entries()) {
        result[key] = value;
      }
      return result;
    }
  
    /**
     * 检查对象是否有某个属性
     * @param obj 要检查的对象
     * @param key 要检查的属性
     * @returns 如果对象有该属性则返回 true，否则返回 false
     */
    static hasProperty<T extends object, K extends keyof T>(obj: T, key: K): boolean {
      return obj.hasOwnProperty(key);
    }
  
    /**
     * 复制对象
     * @param obj 要复制的对象
     * @returns 返回一个新的对象副本
     */
    static clone<T>(obj: T): T {
      return JSON.parse(JSON.stringify(obj));
    }
  
    /**
     * 合并多个对象
     * @param objects 要合并的对象列表
     * @returns 返回一个新的对象，包含所有输入对象的属性
     */
    static mergeObjects<T>(...objects: T[]): T {
      return objects.reduce((acc, obj) => ({ ...acc, ...obj }), {} as T);
    }
  }